/*
 *  Openmysee
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
				 
#include "util.h"
#define MAX_CLIENT	3072
#define MAX_CFG_LINE	1024
#define EscapedChar	"#["
static unsigned char hexchars[] = "0123456789ABCDEF";

struct hostent * init_sockaddr (struct sockaddr_in *name, char *host, unsigned int port)
{
	struct hostent *h;
	unsigned short sp = port;
	memset (name, 0, sizeof (*name));
	name->sin_family = PF_INET;
	name->sin_port = htons (sp);
	h = gethostbyname (host);
	if (h == (struct hostent *)0)
	{
		perror ("gethostbyname");
		return (struct hostent *)0;
	}
	name->sin_addr = *(struct in_addr *)h->h_addr;
	return h;
}

int my_connect (char *host, int port)
{
	struct sockaddr_in client;
	struct hostent *h;
	int connection = socket (PF_INET, SOCK_STREAM, 0);
	if ((connection < 0) || ((h = init_sockaddr (&client, host, port)) == (struct hostent *)0))
	{
		perror ("socket||gethostbyname");
		return -1;
	}
	if (connect (connection, (struct sockaddr *) &client, sizeof (client)) < 0)
	{
		perror ("connect");
		return -1;
	}
	return connection;
}



int init_server (char *ip, unsigned short port)
{
	int		flags;
	struct sockaddr_in server_address;
	int reuse_addr = 1;
	int keep_alive = 1;
	int sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock < 0)
	{
		perror("socket");
		return -1;
	}

	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr));
	setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keep_alive, sizeof(keep_alive));

	flags = fcntl(sock, F_GETFL, 0);
	flags |= O_NONBLOCK;
	fcntl(sock, F_SETFL, flags);

	memset((char *) &server_address, 0, sizeof(server_address));
	server_address.sin_port = htons(port);
	server_address.sin_family = AF_INET;
	//server_address.sin_addr.s_addr = htonl(INADDR_ANY);
	if (ip) inet_aton(ip, &server_address.sin_addr);
	else server_address.sin_addr.s_addr = htonl(INADDR_ANY);
	if (bind(sock, (struct sockaddr *) &server_address, sizeof(server_address)) < 0)
	{
		perror("bind");
		close(sock);
		return -1;
	}
	listen(sock,MAX_CLIENT);
	return sock;
}

int read_config (char *fname, struct NamVal *para, int n)
{
	char *c, *pd;
	struct Array *parray;
	int array[MAX_ARRAY];
	int i, j, len, nlen;
	FILE *f = fopen (fname, "r");
	char buf[MAX_CFG_LINE];	//MAX_LINE = 1024
	if (!f)
	{
		return -1;
	}
	while (fgets (buf, MAX_CFG_LINE, f))
	{
		if (index(EscapedChar, buf[0]))
			continue;
		buf[MAX_CFG_LINE-1] = 0;
		len = strlen (buf);
		while (len > 0 && (buf[len] == 0 || buf[len] == '\n' || buf[len] == '\r' || buf[len] == ' '))
			len --;
		if (len == 0) continue;
		else buf[++len] = 0;
		c = index (buf, '=');
		*c = 0;
		nlen = c - buf;
		for (i=0; i<n; i++)
		{
			if (!strncasecmp (buf, para[i].name, nlen))
				break;
		}
		if (i < n)
			switch (para[i].type)
			{
				case 'd': /* Int type */
					*(int *)(para[i].ptr) = atoi (c+1);
					break;
				case 'a':
					parray = (struct Array *)(para[i].ptr);
					pd = ++c;
					for (j=0; j<MAX_ARRAY; j++)
					{
						while ((*c != 0) && (*c < '0' || *c > '9')) c++;
						if (*c == 0) break;
						array[j] = strtol (c, &pd, 0);
						c = pd;
					}
					if (j > 0)
					{
						para[i].should_free = 1;
						parray->ptr = calloc (j, sizeof (int));
						memcpy (parray->ptr, array, sizeof (int)*j);
					}
					parray->size = j;
					break;
				case 'f': /* float type */
					*(float *)(para[i].ptr) = atof (c+1);
					break;
				case 's': /* Char string */
					if (len > nlen)
					{
						*(char **)(para[i].ptr) = (char *)calloc (len-nlen, 1);
						para[i].should_free = 1;
						memcpy (*(char **)(para[i].ptr), c+1, len-nlen);
					} else
						*(char **)(para[i].ptr) = 0;
					break;
				case 'b': /* Buffer type */
					if (len > nlen)
						memcpy ((char *)(para[i].ptr), c+1, len-nlen);
					else
						*(char *)para[i].ptr = 0;
					break;
				default:
					break;
			}
		else
			continue;
	}
	fclose (f);
	return 0;
}
/*
int main (int argc, char **argv)
{
	read_config ("./ats.cfg", ConfigParameters, sizeof (ConfigParameters)/sizeof(struct NamVal));
	PDEBUG ("%s %s %s %d\n", g, p, l, s);
	return 0;
}
*/
int free_config (struct NamVal *nv, int n)
{
	int i;
	for (i=0; i<n; i++)
	{
		switch (nv[i].type)
		{
			case 'a':
				if ((struct Array *)(nv[i].ptr) != NULL && nv[i].should_free == 1)
					free (((struct Array *)(nv[i].ptr))->ptr);
				break;
			case 's':
				if (*(char **)(nv[i].ptr) != NULL && nv[i].should_free == 1)
					free (*(char **)(nv[i].ptr));
				break;
			default:
				break;
		}
	}
	return 0;
}

int init_udp (char *ip, unsigned short port)
{
	int s = socket (PF_INET, SOCK_DGRAM, 0);
	struct sockaddr_in send;
	send.sin_port = htons(port);
	send.sin_family = AF_INET;
	if (ip) inet_aton(ip, &send.sin_addr);
	else send.sin_addr.s_addr = htonl(INADDR_ANY);
	
	if(s < 0 || bind(s, (struct sockaddr*)&send, sizeof(send)) != 0)
	{
		perror("socket|bind");
		close(s);
		return -1;
	}
	return s;
}

int send_udp (int s, char *host, unsigned int port, char *buf, int len)
{
	struct sockaddr_in server;
	struct hostent *h;
	if ((h = init_sockaddr (&server, host, port)) == (struct hostent *)0)
	{
		perror ("socket||gethostbyname");
		return -1;
	}
	return sendto(s, buf, len, 0, (struct sockaddr*)&server,sizeof(server));
}

int sendMessage (int sock, char *ptr, struct sockaddr_in *dest)
{
	int len = *(int *)ptr;
	int socklen = sizeof (struct sockaddr_in);
	if (sendto (sock, ptr, len, 0, (struct sockaddr *)dest, socklen) != len)
		return -1;
	return len;
}

int
connect_nonb(int sockfd, struct sockaddr_in *saptr, socklen_t salen)
{
	int		flags, n, error;

	flags = fcntl(sockfd, F_GETFL, 0);
	flags |= O_NONBLOCK;
	fcntl(sockfd, F_SETFL, flags);

	error = 0;
	if ( (n = connect (sockfd, (struct sockaddr *) saptr, salen)) < 0)
	{
		if (errno != EINPROGRESS)
		{
			perror ("CP: Connect error:");
			return(-1);
		}
	}

	/* Do whatever we want while the connect is taking place. */
	return flags;
}

#ifdef HAVE_MYSQL
MYSQL *init_mysql (char *host, char *username, char *pass, char *db, char *sock)
{
	MYSQL *mysql = mysql_init (NULL);
	if (mysql == NULL)
	{
		PDEBUG ("mysql_init failed\n");
		return NULL;
	}
	if (mysql_real_connect (mysql, host, username, pass, db, 0, sock, 0) == NULL)
	{
		PDEBUG ("mysql_real_connect failed:%s.\n", mysql_error(mysql));
		return NULL;
	}
	return mysql;
}

int query_mysql (MYSQL *mysql, char *format, ...)
{
	char buffer[MAX_QUERY];
	int len;
	va_list ap;
	va_start (ap, format);
	len = vsnprintf (buffer, MAX_QUERY, format, ap);
	va_end (ap);
	if (len >= MAX_QUERY || len <= -1) return -1;
	if (mysql_query (mysql, buffer) != 0)
	{
		PDEBUG ("Error in query mysql database: %s.\n", mysql_error (mysql));
		return -1;
	}
	return 0;
}

MYSQL_RES *query_mysql_select (MYSQL *mysql, char *format, ...)
{
	char buffer[MAX_QUERY];
	int len;
	va_list ap;
	va_start (ap, format);
	len = vsnprintf (buffer, MAX_QUERY, format, ap);
	va_end (ap);
	if (len >= MAX_QUERY || len <= -1) return NULL;
	if (mysql_query (mysql, buffer) != 0)
	{
		PDEBUG ("Error in query mysql database: %s.\n", mysql_error (mysql));
		return NULL;
	}
	return mysql_store_result (mysql);
}

int authUser (int uid, char *md5, MYSQL *mysql, char *name)
{
	MYSQL_ROW row;
	MYSQL_RES *result_set;
	return 1;
	result_set = query_mysql_select (mysql, "select username from c_reg_users where userid = \"%d\" and password = \"%s\"", uid, md5);
	if (result_set && (row = mysql_fetch_row (result_set)) != NULL)
	{
		if (name) strcpy (name, row[0]);
		return 1;
	}
	if (result_set) mysql_free_result (result_set);
	return 0;
}
#endif
/* {{{ php_url_encode
 *  */
void php_url_encode(char *s, unsigned char *str)
{
	register int x, y;
	int len = strlen (s);
	
	for (x = 0, y = 0; len--; x++, y++) {
		str[y] = (unsigned char) s[x];
		/*      if (str[y] == ' ') {
		 *      *                  str[y] = '+';
		 *      *                          } else*/
		if ((str[y] < '0' && str[y] != '-' && str[y] != '.' && str[y] != '/') ||
				(str[y] < 'A' && str[y] > '9') ||
				(str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||
				(str[y] > 'z')) {
			str[y++] = '%';
			str[y++] = hexchars[(unsigned char) s[x] >> 4];
			str[y] = hexchars[(unsigned char) s[x] & 15];
		}
	}
	str[y] = '\0';
}


char *read_file (char *fname, int *dlen)
{
	register int32_t fd, cc;
	char *cp;
	struct stat buf;

	*dlen = 0;
	if ((fd = open (fname, O_RDONLY)) < 0)
		return NULL;

	if (fstat (fd, &buf) < 0)
		goto ERROR0;

	cp = malloc ((uint32_t) buf.st_size + 1);
	*dlen = buf.st_size;
	if ((cc = read (fd, cp, (int) buf.st_size)) < 0 || cc != buf.st_size)
		goto ERROR;
	cp[(int) buf.st_size] = '\0';
	close (fd);
	return (cp);
ERROR:
	free (cp);
ERROR0:
	close (fd);
	perror ("read_file:");
	return NULL;
}
